package karma.pool.pool;

import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.Callable;

import static java.util.concurrent.TimeUnit.SECONDS;
import static karma.pool.util.UtilityElf.quietlySleep;

/**
 * Creating and adding poolEntries (connections) to the pool.
 */
@Slf4j
final class PoolEntryCreator implements Callable<Boolean> {
   private final String loggingPrefix;
   private Pool pool;

   PoolEntryCreator(Pool pool, String loggingPrefix) {
      this.pool = pool;
      this.loggingPrefix = loggingPrefix;
   }

   @Override
   public Boolean call() {
      long sleepBackoff = 250L;
      while (pool.poolState == Pool.POOL_NORMAL && shouldCreateAnotherConnection()) {
         final PoolEntry poolEntry = pool.createPoolEntry();
         if (poolEntry != null) {
            pool.bag.add(poolEntry);
            log.debug("{} - Added proxyConnection {}", pool.poolName, poolEntry.connection);
            if (loggingPrefix != null) {
               pool.logPoolState(loggingPrefix);
            }
            return Boolean.TRUE;
         }

         // failed to get proxyConnection from db, sleep and retry
         quietlySleep(sleepBackoff);
         sleepBackoff = Math.min(SECONDS.toMillis(10), Math.min(pool.connectionTimeout, (long) (sleepBackoff * 1.5)));
      }
      // Pool is suspended or shutdown or at max size
      return Boolean.FALSE;
   }

   /**
    * We only create connections if we need another idle proxyConnection or have threads still waiting
    * for a new proxyConnection.  Otherwise we bail out of the request to create.
    *
    * @return true if we should create a proxyConnection, false if the need has disappeared
    */
   private synchronized boolean shouldCreateAnotherConnection() {
      return pool.getTotalConnections() < pool.configuration.getMaximumPoolSize() &&
         (pool.bag.getWaitingThreadCount() > 0 || pool.getIdleConnections() < pool.configuration.getMinimumIdle());
   }
}
